package com.fcgzs.search.service.impl;

import com.alibaba.fastjson.JSON;
import com.fcgzs.entity.Result;
import com.fcgzs.search.SkuInfo;
import com.fcgzs.search.dao.SearchMapper;
import com.fcgzs.search.service.SearchService;
import com.fcgzs.sellergoods.feign.ItemFeign;
import com.fcgzs.sellergoods.pojo.Item;
import org.apache.commons.lang.StringUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.*;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.*;

/**
 * @Auther: ljj
 * @Description:
 */
@Service
public class SearchServiceImpl implements SearchService {

    @Autowired
    private ItemFeign itemFeign;

    @Autowired
    private SearchMapper searchMapper;

    @Autowired
    private ElasticsearchRestTemplate restTemplate;

    /**
     * 向搜索引擎导入SKU数据
     */
    @Override
    public void importSku() {
        //1.远程调用查询SKU列表的方法获取数据
        Result<List<Item>> result = itemFeign.findByStatus("1");
        List<SkuInfo> itemList = JSON.parseArray(JSON.toJSONString(result.getData()), SkuInfo.class);    //深克隆

        if (!CollectionUtils.isEmpty(itemList)) {
            for (SkuInfo skuInfo : itemList) {
                //{"机身内存":"16G","网络":"联通3G"}
                Map<String, Object> specMap = JSON.parseObject(skuInfo.getSpec(), Map.class);
                skuInfo.setSpecMap(specMap);
            }
        }

        //2.执行向ES中导入
        searchMapper.saveAll(itemList);

    }

    /**
     * 查询SKU数据
     *
     * @param searchMap
     * @return
     */
    @Override
    public Map search(Map<String, Object> searchMap) {
        Map resultMap = new HashMap();
        //1.获取查询关键字，并处理
        String keywords = (String) searchMap.get("keywords");
        if (StringUtils.isEmpty(keywords)) {
            keywords = "华为";
        }
        //2.创建查询对象的构建对象
        NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
        //-----分组查询开始-----
        //terms   分组查询后的列名  field  根据哪一列分组
        nativeSearchQueryBuilder.addAggregation(AggregationBuilders.terms("skuCategoryGroup").field("category"));
        nativeSearchQueryBuilder.addAggregation(AggregationBuilders.terms("skuBrandGroup").field("brand"));
        nativeSearchQueryBuilder.addAggregation(AggregationBuilders.terms("skuSpecGroup").field("spec.keyword"));
        //-----分组查询结束-----


        //-------条件筛选开始---------
        //获取条件筛选查询对象
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        //分类筛选
        if (StringUtils.isNotEmpty((String) searchMap.get("category"))) {
            boolQueryBuilder.filter(QueryBuilders.matchQuery("category", (String) searchMap.get("category")));
        }
        //品牌筛选
        if (StringUtils.isNotEmpty((String) searchMap.get("brand"))) {
            boolQueryBuilder.filter(QueryBuilders.matchQuery("brand", (String) searchMap.get("brand")));
        }
        //规格筛选
        if (null != searchMap) {

            for (String key : searchMap.keySet()) {
                //判断查询条件中key是否含有 spec_
                if (key.startsWith("spec_")) {
                    boolQueryBuilder.filter(QueryBuilders.matchQuery("specMap." + key.substring(5) + ".keyword", searchMap.get(key)));
                }
            }
        }

        //价格
        if (StringUtils.isNotEmpty((String) searchMap.get("price"))) {
            //0-1500  0 1500  strings[0] 0  strings[1] 1500
            String price = (String) searchMap.get("price");
            String[] strings = price.split("-");
            if (!strings[0].equals("0")) {
                boolQueryBuilder.filter(QueryBuilders.rangeQuery("price").gte(strings[0]));
            }
            if (!strings[1].equals("*")) {
                boolQueryBuilder.filter(QueryBuilders.rangeQuery("price").lt(strings[1]));
            }

        }


        nativeSearchQueryBuilder.withFilter(boolQueryBuilder);
        //-------条件筛选结束---------

        //分页查询
        Integer pageNum = 1;
        if (null == searchMap.get("pageNum")) {
            pageNum = 1;
        } else {
            try {
                pageNum = Integer.parseInt((String) searchMap.get("pageNum"));
            } catch (NumberFormatException e) {
                e.printStackTrace();
                pageNum = 1;
            }
        }
        Integer pageSize = 10;


        nativeSearchQueryBuilder.withPageable(PageRequest.of(pageNum - 1, pageSize));

        //排序
        if (StringUtils.isNotEmpty((String) searchMap.get("sortField")) && StringUtils.isNotEmpty((String) searchMap.get("sort"))) {
            nativeSearchQueryBuilder.withSort(SortBuilders.fieldSort((String) searchMap.get("sortField")).order(((String) searchMap.get("sort")).equals("DESC") ? SortOrder.DESC : SortOrder.ASC));
        }

        //高亮显示
        nativeSearchQueryBuilder.withHighlightFields(new HighlightBuilder.Field("title"));
        nativeSearchQueryBuilder.withHighlightBuilder(new HighlightBuilder().preTags("<em style=\"color:red\">").postTags("</em>"));


        //3.在构建对象中设置查询条件
        //QueryBuilders.matchQuery() 对查询条件做拆词处理 华为  华 为     multiMatchQuery() 不做拆词处理 华为
        //nativeSearchQueryBuilder.withQuery(QueryBuilders.matchQuery("title", keywords));
        nativeSearchQueryBuilder.withQuery(QueryBuilders.multiMatchQuery(keywords,"title","brand","category"));
        //4.创建查询对象
        NativeSearchQuery query = nativeSearchQueryBuilder.build();
        //5.执行条件查询
        SearchHits<SkuInfo> searchHits = restTemplate.search(query, SkuInfo.class);

        //针对高亮结果处理，将不显示高亮的内容替换成高亮的内容
        for (SearchHit<SkuInfo> searchHit : searchHits) {
            Map<String, List<String>> highlightFields = searchHit.getHighlightFields();
            searchHit.getContent().setTitle(highlightFields.get("title")==null?searchHit.getContent().getTitle():highlightFields.get("title").get(0));
        }


        //6.对查询结果做分页处理
        SearchPage<SkuInfo> searchPage = SearchHitSupport.searchPageFor(searchHits, query.getPageable());
        //对分组结果做处理
        Terms categoryGroup = searchHits.getAggregations().get("skuCategoryGroup");
        List<String> categoryList = this.getGroupList(categoryGroup);

        Terms brandGroup = searchHits.getAggregations().get("skuBrandGroup");
        List<String> brandList = this.getGroupList(brandGroup);

        Terms specGroup = searchHits.getAggregations().get("skuSpecGroup");
        Map<String, Set<String>> specMap = this.getSpecGroupMap(specGroup);


        //7.重新封装返回结果
        List<SkuInfo> list = new ArrayList<>();
        for (SearchHit<SkuInfo> searchHit : searchPage.getSearchHits()) {
            SkuInfo content = searchHit.getContent();
            //封装
            SkuInfo skuInfo = new SkuInfo();
            //content--> skuInfo
            BeanUtils.copyProperties(content, skuInfo);   //注意： 使用该复制属性方法，两边类中的属性一定要名称、类型保持一致
            list.add(skuInfo);
        }
        //8.返回查询数据
        resultMap.put("rows", list);    //获取结果集
        resultMap.put("total", searchHits.getTotalHits());  //获取总记录数
        resultMap.put("totalPages", searchPage.getTotalPages());   //获取总页数
        resultMap.put("categoryList", categoryList);   //分类的分组统计结果
        resultMap.put("brandList", brandList);    //品牌的分组统计结果
        resultMap.put("specMap", specMap);      //规格的分组统计结果
        return resultMap;
    }


    private List<String> getGroupList(Terms terms) {
        List<String> groupList = new ArrayList<>();
        for (Terms.Bucket bucket : terms.getBuckets()) {
            String key = bucket.getKeyAsString();
            groupList.add(key);
        }
        return groupList;
    }

    private Map<String, Set<String>> getSpecGroupMap(Terms terms) {
        Map<String, Set<String>> resultMap = new HashMap<>();

        //{"机身内存":"128G","网络":"电信4G"}
        Set<String> specSet = new HashSet<>();
        for (Terms.Bucket bucket : terms.getBuckets()) {
            //1.对查询结果重新去重
            specSet.add(bucket.getKeyAsString());
        }

        for (String specJson : specSet) {
            //将JSON类型的字符串转换为Map对象
            Map<String, String> map = JSON.parseObject(specJson, Map.class);


            for (Map.Entry<String, String> entry : map.entrySet()) {
                String key = entry.getKey();   //得到规格名称


                Set<String> valueSet = resultMap.get(key);
                if (valueSet == null) {
                    valueSet = new HashSet<>();
                }
                valueSet.add(entry.getValue());   //得到规格选项

                resultMap.put(key, valueSet);
            }

        }
        return resultMap;
    }
}
